/* --------------------------------------------------------------------------------
 * PropellentNet: Propeller IDE
 * Copyright 2008 - Jason Wood
 * --------------------------------------------------------------------------------
 * BaseObjects.cs
 * Container of the default SpinCodeObjects.
 * --------------------------------------------------------------------------------
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * --------------------------------------------------------------------------------
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;

namespace PropellentNet
{
    
    #region Blocks
    [SearchEngine("Block")]
    public class BlockEngine : CodeSearchEngine
    {
        public BlockEngine()
            : base(@"(?<![^?])(con|obj|pub|pri|dat|var)(?=( |\r\n|\t))")
        {
        }


        /// <summary>
        /// Override of base.Search
        /// </summary>
        /// <param name="searchStr"></param>
        /// <param name="SearchStream"></param>
        /// <param name="currentPos"></param>
        /// <param name="currentChar"></param>
        /// <param name="currentLine"></param>
        /// <returns> An array of found objects </returns>
        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                string holdMatchValue = foundMatch.Value;

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);
                    //holdMatchValue = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                //searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Block tmpCmt = new Block();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - (searchStr.Length - foundMatch.Index) + 1);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                if (foundMatch.Value.Length < searchStr.Length - foundMatch.Index)
                {
                    currentPos -= foundMatch.Value.Length + foundMatch.Index - 1;
                    currentChar -= foundMatch.Value.Length + foundMatch.Index - 1;
                }

                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("Block")]
    public class Block : SpinCodeObject
    {
        public Block()
            : base(null, "Block")
        {
        }

        public static void RegisterParams()
        {
            base.RegisterParameters();
            base.TextColor = Color.Black;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = true;
        }
        
    }
    #endregion Blocks
    
    #region Comments
    [SearchEngine("Comments")]
    public class CommentsEngine : CodeSearchEngine
    {

        private string m_RegexEndSearch;

        private Hashtable m_MoreEngines;

        public CommentsEngine()
            : base(@"'(?=[^'])|''|{(?=[^{])|{{") //@"'(?!')|''|{(?!{)|{{")
        {
            m_MoreEngines = new Hashtable();
            m_MoreEngines.Add("'", new Regex("\r\n"));
            m_MoreEngines.Add("''", new Regex("\r\n"));
            m_MoreEngines.Add("{", new Regex("}"));
            m_MoreEngines.Add("{{", new Regex("}}"));
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    //m_SpinObjects.Add(tmpObj);
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                Comments tmpCmt = new Comments();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - searchStr.Length + 1);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);
                
                holdObjects.AddRange(SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos, ref currentChar, ref currentLine));
                
                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                currentLine += searchStr.Split(new string[] { "\r\n" }, StringSplitOptions.None).Length - 1;
                if (searchStr.EndsWith("\r\n"))
                    currentChar = 0;
                else
                    currentChar += searchStr.Length-2;
                
                return returnObjs;

            }
            else
                return null;

        }

        private SpinCodeObject[] SearchForEnd(Regex LooknFor, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {
            
            string searchStr = "";
            Match foundMatch = null;
            
            ArrayList holdSCO = new ArrayList();
            
            while (++currentPos < SearchStream.Length)
            {
                currentChar++;
                searchStr += SearchStream[currentPos];
                
                if ((foundMatch = LooknFor.Match(searchStr)) != Match.Empty)
                {
                    
                    Comments tmpCmt = new Comments();
                    tmpCmt.EditorLocation = new Location(currentLine, currentChar - searchStr.Length + 1);
                    tmpCmt.ObjectText = searchStr.Replace("\r\n", "");
                    holdSCO.Add(tmpCmt);

                    if (searchStr.EndsWith("\r\n"))
                    {
                        tmpCmt = new Comments();
                        tmpCmt.EditorLocation = new Location(currentLine, currentChar - searchStr.Length + 1);
                        tmpCmt.ObjectText = searchStr.Replace("\r\n", "");
                        holdSCO.Add(tmpCmt);

                        currentLine++;
                        currentChar = 0;

                        searchStr = "";
                    }
                    
                    break;
                }
                else if (searchStr.IndexOf("\r\n") > -1)
                {
                    Comments tmpCmt = new Comments();
                    tmpCmt.EditorLocation = new Location(currentLine, currentChar - searchStr.Length + 1);
                    tmpCmt.ObjectText = searchStr.Replace("\r\n", "");
                    holdSCO.Add(tmpCmt);

                    currentLine++;
                    currentChar = 0;

                    searchStr = "";

                }
                
            }

            SpinCodeObject[] returnObjs = new SpinCodeObject[holdSCO.Count];
            holdSCO.CopyTo(returnObjs);

            return returnObjs;

        }

    }
    [SpinType("Comments")]
    public class Comments : SpinCodeObject
    {

        public Comments()
            : base(null, "Comments")
        {
            base.TextColor = Color.Brown;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = false;
        }

    }
    #endregion Comments
    
    #region Text
    [SearchEngine("Text")]
    public class TextEngine : CodeSearchEngine
    {

        private string m_RegexEndSearch;

        private Hashtable m_MoreEngines;

        public TextEngine()
            : base("\"") //@"'(?!')|''|{(?!{)|{{")
        {
            m_MoreEngines = new Hashtable();
            m_MoreEngines.Add("\"", new Regex("\""));
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    //m_SpinObjects.Add(tmpObj);
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Text tmpCmt = new Text();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                currentLine += searchStr.Split(new string[] { "\r\n" }, StringSplitOptions.None).Length - 1;
                currentChar = 0;

                return returnObjs;

            }
            else
                return null;

        }

        private string SearchForEnd(Regex LooknFor, ref string SearchStream, ref int currentPos)
        {

            string currentStr = "";
            Match holdMatch = null;

            //currentPos--;
            while (currentPos++ < SearchStream.Length)
            {

                currentStr += SearchStream[currentPos];

                if ((holdMatch = LooknFor.Match(currentStr)) != Match.Empty)
                {
                    if (holdMatch.Value.Length < currentStr.Length)
                    {
                        //currentPos -= currentStr.Length - holdMatch.Value.Length;
                        //currentStr = holdMatch.Value;
                    }
                    break;
                }

            }

            return currentStr;

        }

    }
    [SpinType("Text")]
    public class Text : SpinCodeObject
    {

        public Text()
            : base(null, "Text")
        {
            base.TextColor = Color.Red;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = false;
        }

    }
    #endregion Comments
    
    #region Commands
    [SearchEngine("Commands")]
    public class CommandsEngine : CodeSearchEngine
    {
        public CommandsEngine()
            : base(@"(abort|bytefill|cognew|lookup|quit|return|waitcnt)(?=( |\())")
        {
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                string holdMatchValue = foundMatch.Value;

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);
                    //holdMatchValue = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                //searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Block tmpCmt = new Block();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - (searchStr.Length - foundMatch.Index) + 1);
                tmpCmt.ObjectText = foundMatch.Value;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                if (foundMatch.Value.Length < searchStr.Length)
                {
                    currentPos -= searchStr.Length - foundMatch.Value.Length;
                    currentChar -= searchStr.Length - foundMatch.Value.Length;
                }
                else if (foundMatch.Value.Length < searchStr.Length - foundMatch.Index)
                {
                    currentPos -= foundMatch.Value.Length + foundMatch.Index - 1;
                    currentChar -= foundMatch.Value.Length + foundMatch.Index - 1;
                }

                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("Commands")]
    public class Commands : SpinCodeObject
    {

        public Commands()
            : base(null, "Commands")
        {
            base.TextColor = Color.Brown;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = true;
        }

    }
    #endregion Commands
    
    #region Conditional
    [SearchEngine("Conditional")]
    public class ConditionalEngine : CodeSearchEngine
    {
        public ConditionalEngine()
            : base(@"((if|case|repeat|while|until)(?=( |\()))|else(?=( |\r\n))")
        {
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                string holdMatchValue = foundMatch.Value;

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);
                    //holdMatchValue = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                //searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Block tmpCmt = new Block();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - (searchStr.Length - foundMatch.Index) + 1);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("Conditional")]
    public class Conditional : SpinCodeObject
    {

        public Conditional()
            : base(null, "Conditional")
        {
            base.TextColor = Color.Blue;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = true;
        }

    }
    #endregion Conditional
    
    #region Variables
    [SearchEngine("Variables")]
    public class VariablesEngine : CodeSearchEngine
    {
        public VariablesEngine()
            : base(@" result|spr")
        {
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                string holdMatchValue = foundMatch.Value;

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);
                    //holdMatchValue = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                //searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Block tmpCmt = new Block();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - (searchStr.Length - foundMatch.Index) + 1);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("Variables")]
    public class Variables : SpinCodeObject
    {

        public Variables()
            : base(null, "Variables")
        {
            base.TextColor = Color.Yellow;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = true;
        }

    }
    #endregion Variables
    
    #region Directives
    [SearchEngine("Directives")]
    public class DirectivesEngine : CodeSearchEngine
    {
        public DirectivesEngine()
            : base(@"(long|float|round|trunc|constant|string)(?= )")
        {
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                string holdMatchValue = foundMatch.Value;

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);
                    //holdMatchValue = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                //searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Block tmpCmt = new Block();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - (searchStr.Length - foundMatch.Index) + 1);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("Directives")]
    public class Directives : SpinCodeObject
    {

        public Directives()
            : base(null, "Directives")
        {
            base.TextColor = Color.Purple;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = true;
        }

    }
    #endregion Directives
    
    #region Operators
    [SearchEngine("Operators")]
    public class OperatorsEngine : CodeSearchEngine
    {
        public OperatorsEngine()
            : base(@"(@|AND|NOT|\+|-|>>|<<|\|\*|\||=(?=[^=])|==|:=|\^|&|:(?=[^=]))")
        {
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                string holdMatchValue = foundMatch.Value;

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);
                    //holdMatchValue = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                //searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Operators tmpCmt = new Operators();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - searchStr.Length + 1);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("Operators")]
    public class Operators : SpinCodeObject
    {

        public Operators()
            : base(null, "Operators")
        {
            base.TextColor = Color.Green;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = true;
        }

    }
    #endregion Operators
    
    #region Numbers
    [SearchEngine("Numbers")]
    public class NumbersEngine : CodeSearchEngine
    {
        public NumbersEngine()
            : base(@"[^a-zA-Z\[][-+]?[0-9]*\.?[0-9]+(?=[^0-9])|(?<![a-zA-Z\[])[0-9]+(?=[^\.])(?=[^0-9])") //
        {
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                string holdMatchValue = foundMatch.Value;

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);
                    //holdMatchValue = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                //searchStr += SearchForEnd((Regex)m_MoreEngines[foundMatch.Value], ref SearchStream, ref currentPos);

                Numbers tmpCmt = new Numbers();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar - searchStr.Length + 1);
                tmpCmt.ObjectText = foundMatch.Value;
                holdObjects.Add(tmpCmt);

                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                if (foundMatch.Value.Length < searchStr.Length)
                {
                    currentPos -= searchStr.Length - foundMatch.Value.Length;
                    currentChar -= searchStr.Length - foundMatch.Value.Length;
                }
                else if (foundMatch.Value.Length < searchStr.Length - foundMatch.Index)
                {
                    currentPos -= foundMatch.Value.Length + foundMatch.Index - 1;
                    currentChar -= foundMatch.Value.Length + foundMatch.Index - 1;
                }
                
                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("Numbers")]
    public class Numbers : SpinCodeObject
    {

        public Numbers()
            : base(null, "Numbers")
        {
            base.TextColor = Color.Teal;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = false;
        }

    }
    #endregion Operators
    
    #region TextFormating
    [SearchEngine("TextFormating")]
    public class TextFormatingEngine : CodeSearchEngine
    {
        public TextFormatingEngine()
            : base(@" |\r\n|\t")
        {
        }

        public override SpinCodeObject[] Search(string searchStr, ref string SearchStream, ref int currentPos, ref int currentChar, ref int currentLine)
        {

            ArrayList holdObjects = new ArrayList();

            Match foundMatch = null;
            if ((foundMatch = base.SearchEngine.Match(searchStr)) != Match.Empty)
            {

                /// If we found a match but it doesn't start 
                /// at the begining of the string. That means
                /// we dont have a valid object before the current
                /// match. We need to mark that section as such.
                if (foundMatch.Index != 0)
                {

                    /// Create new SpintCode Object based on 
                    /// the type that found the current match
                    SpinCodeObject tmpObj = new Unknown();

                    /// set current object text = to the start of the
                    /// search string and end at the match start. 
                    tmpObj.ObjectText = searchStr.Substring(0, foundMatch.Index);

                    /// build a new text Location object with the current char and line 
                    Location tmploc = new Location();
                    tmploc.CharIndex = currentChar - searchStr.Length + 1;
                    tmploc.LineNumber = currentLine;
                    tmpObj.EditorLocation = tmploc;

                    /// Add object to arraylist 
                    //m_SpinObjects.Add(tmpObj);
                    holdObjects.Add(tmpObj);

                    /// Remove this preceding unknown object from the Match text
                    searchStr = searchStr.Substring(foundMatch.Index, (searchStr.Length) - foundMatch.Index);

                }

                ArrayList tmpList = new ArrayList();

                TextFormating tmpCmt = new TextFormating();
                tmpCmt.EditorLocation = new Location(currentLine, currentChar);
                tmpCmt.ObjectText = searchStr;
                holdObjects.Add(tmpCmt);
                
                switch (foundMatch.Value)
                {
                    case "\r\n":
                        currentLine += 1;
                        currentChar = 0;
                        break;
                    case "\t":
                        currentChar += 5;
                        break;
                    default:
                        break;
                }
                
                SpinCodeObject[] returnObjs = new SpinCodeObject[holdObjects.Count];
                holdObjects.CopyTo(returnObjs);

                return returnObjs;

            }
            else
                return null;

        }

    }
    [SpinType("TextFormating")]
    public class TextFormating : SpinCodeObject
    {
        public TextFormating()
            : base(null, "TextFormating")
        {
            base.TextColor = Color.Black;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = false;
        }
    }
    #endregion TextFormating
    
    #region Unknow
    [SpinType("Unknown")]
    public class Unknown : SpinCodeObject
    {

        public Unknown()
            : base(null, "Unknown")
        {
            base.TextColor = Color.Black;
            base.BackgroundColor = Color.Transparent;
            base.IsBold = false;
        }

    }
    #endregion Unknow
    
}
